package com.java.permission.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.java.permission.common.dao.entity.SysOffice;
import com.java.permission.common.dao.mapper.SysOfficeMapper;
import com.java.permission.common.dto.SysOfficeDto;
import com.java.permission.common.enums.DataStatusEnum;
import com.java.permission.common.enums.YesOrNoEnums;
import com.java.permission.common.exception.MessageException;
import com.java.permission.common.exception.ParamsException;
import com.java.permission.common.service.BaseService;
import com.java.permission.common.service.SysOfficeService;
import com.java.permission.common.utils.IdUtils;
import com.java.permission.common.utils.SysOfficeParentIdsUtils;
import com.java.permission.common.vo.SysOfficeTreeVo;
import org.apache.commons.collections4.CollectionUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author hu
 * @version 1.0
 * @date 2020/6/12 10:08
 * @description
 */
@Service
public class SysOfficeServiceImpl extends BaseService implements SysOfficeService  {

    @Resource
    private SysOfficeMapper sysOfficeMapper;

    @Override
    public SysOffice findValidById(String id) {
        LambdaQueryWrapper<SysOffice> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(SysOffice::getId, id)
                .eq(SysOffice::getStatus, DataStatusEnum.NORMAL.getCode());
        return sysOfficeMapper.selectOne(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(SysOfficeDto sysOfficeDto, String operUserId) {
        //新增 顶底部门 非顶级部门
        // 当前层级 部门名称是否存在 排序是否存在
        // 部门类型 是否一致
        // 非顶级部门 父部门是否存在 是否被停用
        // 新增之后 调整父部门
        LocalDateTime now = LocalDateTime.now();
        SysOffice sysOffice;
        SysOffice parentOffice = null;
        if (SysOfficeParentIdsUtils.ROOT.equals(sysOfficeDto.getParentId())) {
            List<SysOffice> firstLevelOffices = this.findAllFistLevelOffice();
            if (CollectionUtils.isNotEmpty(firstLevelOffices)) {
                firstLevelOffices.stream().filter(office -> office.getOfficeName().equals(sysOfficeDto.getOfficeName())).findFirst().ifPresent(office -> {
                    throw new ParamsException("机构名称已存在");
                });
            }
            sysOffice = new SysOffice();
            BeanUtils.copyProperties(sysOfficeDto, sysOffice);
            sysOffice.setId(IdUtils.newId());
            sysOffice.setParentIds(SysOfficeParentIdsUtils.calculateParentIds(null, sysOffice.getParentId()));
            sysOffice.setTreeLeaf(Integer.valueOf(YesOrNoEnums.YES.getCode()));
            sysOffice.setTreeLevel(1);
            sysOffice.setTreeNames(sysOfficeDto.getOfficeName() + "/");
        } else {
           parentOffice = this.findOfficeById(sysOfficeDto.getParentId());
            if (parentOffice == null) {
                throw new MessageException("当前父机构不存在");
            }
            if (parentOffice.getStatus().equals(DataStatusEnum.DISABLED.getCode())) {
                throw new MessageException("当前父机构已被停用");
            }
            List<SysOffice> childOfficeList = this.findAllChildOfficeById(sysOfficeDto.getParentId());
            if (CollectionUtils.isNotEmpty(childOfficeList)) {
                childOfficeList.stream().filter(office -> office.getOfficeName().equals(sysOfficeDto.getOfficeName())).findFirst().ifPresent(office -> {
                    throw new ParamsException("当前机构名称已存在!");
                });
            }
            sysOffice = new SysOffice();
            BeanUtils.copyProperties(sysOfficeDto, sysOffice);
            sysOffice.setId(IdUtils.newId());
            sysOffice.setParentIds(SysOfficeParentIdsUtils.calculateParentIds(parentOffice.getParentIds(), parentOffice.getId()));
            sysOffice.setTreeLeaf(Integer.valueOf(YesOrNoEnums.YES.getCode()));
            sysOffice.setTreeLevel(parentOffice.getTreeLevel() + 1);
            sysOffice.setTreeNames(parentOffice.getTreeNames() + sysOfficeDto.getOfficeName() + "/");
        }
        sysOffice.setCreateAt(now);
        sysOffice.setUpdateAt(now);
        sysOffice.setCreateBy(operUserId);
        sysOffice.setUpdateBy(operUserId);
        sysOfficeMapper.insert(sysOffice);

        //调整父机构
        if (parentOffice != null && parentOffice.getTreeLeaf() == 1) {
            this.updateParentOffice(parentOffice, operUserId);
        }
    }

    @Override
    public void edit(SysOfficeDto sysOfficeDto, String operUserId) {
        //部门是否存在 是否停用 // 修改后的名称是否存在
        // 父机构是否存在
        // 父机构是否调整
        //是否需要调整子部门 // 父机构是否存在 是否需要调整
        //移动之后的父机构是否存在 是否停用 是否需要调整
        SysOffice updateBefore = this.findOfficeById(sysOfficeDto.getId());
        if (updateBefore == null) {
            throw new ParamsException("当前机构不存在!");
        }
        if (updateBefore.getStatus().equals(DataStatusEnum.DISABLED.getCode())) {
            throw new ParamsException("当前机构已被停用！");
        }
        SysOffice parentOffice = this.findOfficeById(sysOfficeDto.getParentId());
        if (parentOffice == null) {
            throw new ParamsException("当前父机构不存在!");
        }
        if (parentOffice.getStatus().equals(DataStatusEnum.DISABLED.getCode())) {
            throw new ParamsException("当前父机构已被停用！");
        }
        updateBefore.setUpdateAt(LocalDateTime.now());
        updateBefore.setUpdateBy(operUserId);
        updateBefore.setOfficeName(sysOfficeDto.getOfficeName());
        updateBefore.setTreeSort(sysOfficeDto.getTreeSort());
        updateBefore.setRemark(sysOfficeDto.getRemark());
        updateBefore.setOfficeCode(sysOfficeDto.getOfficeCode());
        updateBefore.setOfficeType(sysOfficeDto.getOfficeType());
        updateBefore.setTreeNames(parentOffice.getTreeNames() + sysOfficeDto.getOfficeName() + "/");
        // 父机构没有调整
        if(updateBefore.getParentId().equals(sysOfficeDto.getParentId())) {
            sysOfficeMapper.updateById(updateBefore);
        } else {
           //父机构变化
            updateBefore.setParentIds(SysOfficeParentIdsUtils.calculateParentIds(parentOffice.getParentIds(), parentOffice.getId()));
            //父机构调整前 原父机构
            SysOffice originParentSysOffice = this.findOfficeById(updateBefore.getParentId());
            List<SysOffice> originParentOfficeChildren = this.findAllChildOfficeById(originParentSysOffice.getId());

           if (CollectionUtils.isNotEmpty(originParentOfficeChildren)) {
               SysOffice sysOfficeTemp = originParentOfficeChildren.stream().filter(office -> !office.getId().equals(sysOfficeDto.getId())).findFirst().orElse(null);
               if (sysOfficeTemp == null) {
                   originParentSysOffice.setTreeLeaf(1);
                   originParentSysOffice.setUpdateBy(operUserId);
                   originParentSysOffice.setUpdateAt(LocalDateTime.now());
                   sysOfficeMapper.updateById(originParentSysOffice);
               }

           }
            List<SysOffice> originChildrenOffice = this.findAllChildOfficeById(sysOfficeDto.getId());
           if (CollectionUtils.isNotEmpty(originChildrenOffice)) {
               for (SysOffice sysOffice : originChildrenOffice) {
                   int flag = sysOffice.getParentIds().indexOf(sysOfficeDto.getId());
                   int nameFlag = sysOffice.getTreeNames().indexOf(updateBefore.getOfficeName());
                   if (flag != -1) {
                       String subParents = sysOffice.getParentIds().substring(flag);
                       String parentIds = parentOffice.getParentIds();
                       if (parentIds.endsWith(",")) {
                           sysOffice.setParentIds(parentIds + subParents);
                       } else {
                           sysOffice.setParentIds(parentIds + "," + subParents);
                       }
                   }
                  if (nameFlag != -1) {
                      String subTreeName = sysOffice.getTreeNames().substring(nameFlag);
                      String parentTreeNames = parentOffice.getTreeNames();
                      sysOffice.setTreeNames(parentTreeNames + subTreeName);
                  }
                  sysOffice.setUpdateAt(LocalDateTime.now());
                  sysOffice.setUpdateBy(operUserId);
                  sysOfficeMapper.updateById(sysOffice);
               }
           }
           //调整父机构
            if (parentOffice.getTreeLeaf() == 0) {
                this.updateParentOffice(parentOffice, operUserId);
            }
            sysOfficeMapper.updateById(updateBefore);
        }

    }

    @Override
    public List<SysOfficeTreeVo> getSysOfficeTree() {
        List<SysOffice> sysOfficeList = this.findAllSysOffice();
        if (CollectionUtils .isEmpty(sysOfficeList)) {
            return  new ArrayList<>();
        }
        List<SysOfficeTreeVo> sysOfficeTreeVoList = Lists.newArrayList();
        for (SysOffice sysOffice : sysOfficeList) {
            SysOfficeTreeVo sysOfficeTreeVo = new SysOfficeTreeVo();
            BeanUtils.copyProperties(sysOffice, sysOfficeTreeVo);
            sysOfficeTreeVo.setChildren(Lists.newArrayList() );
            sysOfficeTreeVoList.add(sysOfficeTreeVo);
        }
        List<SysOfficeTreeVo> rootList = Lists.newArrayList();
        Multimap<String, SysOfficeTreeVo> sysOfficeTreeVoMultimap = ArrayListMultimap.create();
        for (SysOfficeTreeVo sysOfficeTreeVo : sysOfficeTreeVoList) {
            if (SysOfficeParentIdsUtils.ROOT.equals(sysOfficeTreeVo.getParentId())) {
                rootList.add(sysOfficeTreeVo);
            }
            sysOfficeTreeVoMultimap.put(sysOfficeTreeVo.getParentIds(), sysOfficeTreeVo);
        }
        // 按照treeSort从小到大排序
        rootList.sort(Comparator.comparingInt(SysOfficeDto::getTreeSort));
        this.officeToTree(rootList, SysOfficeParentIdsUtils.ROOT, sysOfficeTreeVoMultimap);
        return null;
    }

    /**
     * 部门递归生成树
     * @param sysOfficeTreeVoList
     * @param parentId
     * @param sysOfficeTreeVoMultimap
     */
    private void officeToTree(List<SysOfficeTreeVo> sysOfficeTreeVoList, String parentId, Multimap<String,SysOfficeTreeVo > sysOfficeTreeVoMultimap) {
        if (!CollectionUtils.isEmpty(sysOfficeTreeVoList)) {
            for (SysOfficeTreeVo sysOfficeTreeVo : sysOfficeTreeVoList) {
                String nextLevel = SysOfficeParentIdsUtils.calculateParentIds(parentId, sysOfficeTreeVo.getId());
                List<SysOfficeTreeVo> childOfficeTreeList =  ( List<SysOfficeTreeVo>)sysOfficeTreeVoMultimap.get(nextLevel);
                if (!CollectionUtils.isEmpty(childOfficeTreeList)) {
                    childOfficeTreeList.sort(Comparator.comparingInt(SysOfficeDto::getTreeSort));
                    sysOfficeTreeVo.setChildren(childOfficeTreeList);
                    this.officeToTree(childOfficeTreeList, nextLevel, sysOfficeTreeVoMultimap );
                }

            }
        }
    }

    /**
     * 查询所有部门
     * @return
     */
    List<SysOffice> findAllSysOffice() {
        LambdaQueryWrapper<SysOffice> query = new LambdaQueryWrapper<>();
        query.ne(SysOffice::getStatus, DataStatusEnum.DETELE.getCode());
       return sysOfficeMapper.selectList(query);
    }

//    public static void main(String[] args) {
//        String str1 = "1/22/3/4";
//        String flag = "22";
//        int i = str1.indexOf(flag);
//        System.out.println(i);
//        String substring = str1.substring(i);
//        System.out.println(substring);
//    }

    /**
     * 根据Id 查询部门信息
     * @param officeId
     * @return
     */
    private  SysOffice findOfficeById(String officeId) {
        LambdaQueryWrapper<SysOffice> query = new LambdaQueryWrapper<>();
        query.ne(SysOffice::getStatus, DataStatusEnum.DETELE.getCode()).eq(SysOffice::getId, officeId);
        return  sysOfficeMapper.selectOne(query);
    }

    /**
     * 查询所有一级机构
     * @return
     */
    private List<SysOffice> findAllFistLevelOffice() {
        LambdaQueryWrapper<SysOffice> query = new LambdaQueryWrapper<>();
        query.ne(SysOffice::getStatus, DataStatusEnum.DETELE.getCode()).eq(SysOffice::getParentId, SysOfficeParentIdsUtils.ROOT);
        return  sysOfficeMapper.selectList(query);
    }

    /**
     * 查询所有子机构
     * @param officeId
     * @return
     */
    private List<SysOffice> findAllChildOfficeById(String officeId) {
        LambdaQueryWrapper<SysOffice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(SysOffice::getStatus, DataStatusEnum.DETELE.getCode()).like(SysOffice::getParentIds, "%," + officeId + ",%");
        return  sysOfficeMapper.selectList(queryWrapper);
    }

    /**
     * 新增 或者修改机构后需调整父机构
     * @param sysOffice
     * @param operUserId
     */
    @Transactional(rollbackFor = Exception.class)
     public void updateParentOffice(SysOffice sysOffice, String operUserId) {
        sysOffice.setTreeLeaf(Integer.valueOf(YesOrNoEnums.NO.getCode()));
        sysOffice.setUpdateBy(operUserId);
        sysOffice.setUpdateAt(LocalDateTime.now());
        sysOfficeMapper.updateById(sysOffice);
    }
}
